package xlog

import (
	"io"
	"sync"
)

// 日志的使用方式一般都是在程序启动的时候获取一个 logger 单例，后续都通过这个单例来调用日志方法记录日志，
// 不同 goroutine 可能并发使用这个单例来记录日志，即使不使用单例，最后把日志输出到文件的时候也会有并发竞争问题，
// 所以必须加锁，
// 如果把所有数据都记录到 logger 对象上，那么要在开始收集数据之前就加锁，接着是数据格式化、输出到文件，最后才解锁，
// 如果加一个 entry 对象池，每次调用日志方法时，先从对象池中获取一个 entry 对象，由它来实现数据收集、格式化、输出到文件，
// 那么只需要在最后输出到文件之前加锁就行了，
// 这样做能有效减少锁的范围，提高性能。
type logger struct {
	// 一把全局锁，控制日志输出时的并发安全
	mu sync.Mutex

	// 全局配置
	opt *options
	// entry 对象池
	entryPool *sync.Pool
}

func New(opts ...Option) *logger {
	logger := &logger{opt: initOptions(opts...)}
	logger.entryPool = &sync.Pool{New: func() interface{} { return entry(logger) }}
	return logger
}

// 一个全局日志对象，方便快速使用
var std = New()

func StdLogger() *logger {
	return std
}

func SetOptions(opt ...Option) {
	std.SetOptions(opt...)
}

// 这个方法让日志对象有了动态修改配置的能力
func (l *logger) SetOptions(opts ...Option) {
	l.mu.Lock()
	defer l.mu.Unlock()

	for _, opt := range opts {
		opt(l.opt)
	}
}

func Writer() io.Writer {
	return std
}

// 实现 io.Writer 接口
func (l *logger) Write(data []byte) (int, error) {
	l.entry().write(l.opt.stdLevel, FmtEmptySeparate, string(data))
	return 0, nil
}

func (l *logger) entry() *Entry {
	return l.entryPool.Get().(*Entry)
}

func (l *logger) Debug(args ...interface{}) {
	l.entry().write(DebugLevel, FmtEmptySeparate, args...)
}

func (l *logger) Info(args ...interface{}) {
	l.entry().write(InfoLevel, FmtEmptySeparate, args...)
}

func (l *logger) Warn(args ...interface{}) {
	l.entry().write(WarnLevel, FmtEmptySeparate, args...)
}

func (l *logger) Error(args ...interface{}) {
	l.entry().write(ErrorLevel, FmtEmptySeparate, args...)
}

func (l *logger) Panic(args ...interface{}) {
	l.entry().write(PanicLevel, FmtEmptySeparate, args...)
}

func (l *logger) Fatal(args ...interface{}) {
	l.entry().write(FatalLevel, FmtEmptySeparate, args...)
}

func (l *logger) Debugf(format string, args ...interface{}) {
	l.entry().write(DebugLevel, format, args...)
}

func (l *logger) Infof(format string, args ...interface{}) {
	l.entry().write(InfoLevel, format, args...)
}

func (l *logger) Warnf(format string, args ...interface{}) {
	l.entry().write(WarnLevel, format, args...)
}

func (l *logger) Errorf(format string, args ...interface{}) {
	l.entry().write(ErrorLevel, format, args...)
}

func (l *logger) Panicf(format string, args ...interface{}) {
	l.entry().write(PanicLevel, format, args...)
}

func (l *logger) Fatalf(format string, args ...interface{}) {
	l.entry().write(FatalLevel, format, args...)
}

func Debug(args ...interface{}) {
	std.entry().write(DebugLevel, FmtEmptySeparate, args...)
}

func Info(args ...interface{}) {
	std.entry().write(InfoLevel, FmtEmptySeparate, args...)
}

func Warn(args ...interface{}) {
	std.entry().write(WarnLevel, FmtEmptySeparate, args...)
}

func Error(args ...interface{}) {
	std.entry().write(ErrorLevel, FmtEmptySeparate, args...)
}

func Panic(args ...interface{}) {
	std.entry().write(PanicLevel, FmtEmptySeparate, args...)
}

func Fatal(args ...interface{}) {
	std.entry().write(FatalLevel, FmtEmptySeparate, args...)
}
